#pragma once
// dynamic vector, size is changable. can own the data or not(different form Array<1, T>)
// when own, = set data, when not own = set reference 
#include "../common.hpp"

namespace zzz{
template <typename T, bool OWN=true>
class DVectorBase
{
public:
  // type definitions
  typedef T              value_type;
  typedef T*             iterator;
  typedef const T*       const_iterator;
  typedef T&             reference;
  typedef const T&       const_reference;
  typedef zsize          size_type;
  typedef size_type      difference_type;

protected:
  T *v;
  zsize size;

public:
  //STL support
  // iterator support
  iterator begin() { return v; }
  const_iterator begin() const { return v; }
  iterator end() { return v+size; }
  const_iterator end() const { return v+size; }

  // reverse iterator support
  typedef std::reverse_iterator<iterator> reverse_iterator;
  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;

  reverse_iterator rbegin() { return reverse_iterator(end()); }
  const_reverse_iterator rbegin() const { return const_reverse_iterator(end());}
  reverse_iterator rend() { return reverse_iterator(begin()); }
  const_reverse_iterator rend() const {return const_reverse_iterator(begin());}

  // at()
  reference at(size_type i) {return v[i]; }
  const_reference at(size_type i) const {return v[i]; }

  // front() and back()
  reference front() { return v[0]; }
  const_reference front() const {  return v[0];}
  reference back() {   return v[size-1]; }
  const_reference back() const {   return v[size-1]; }

  // size is constant
  bool empty() { return v==NULL; }

  // swap (note: linear complexity)
  template<bool OWN1>
  void swap (DVectorBase<T,OWN1>& y) { ZCHECK(size=y.size); std::swap_ranges(begin(),end(), y.begin());}

  //////////////////////////////////////////////////////////////////////////
  // check range (may be private because it is static)
  bool IndexCheck (size_type i) { return (i>=0 && i<size());}

  //subscript
  inline T& operator [](int a) {return v[a];}
  inline const T& operator [](int a) const {return v[a];}

  //positive and negative
  inline const DVectorBase<T,OWN> operator+() const {return *this;}
  inline const DVectorBase<T,true> operator-() const {DVectorBase<T,true> ret; for (unsigned int i=0; i<size; i++) ret.v[i]=-v[i]; return ret;}

  //addition
  template<bool OWN1>
  inline const DVectorBase<T,true> operator+(const DVectorBase<T,OWN1> &a) const {
    DVectorBase<T,true> ret;
    for (unsigned int i=0; i<size; i++)  ret.v[i]=v[i]+a.v[i];
    return ret;
  }
  inline const DVectorBase<T,true> operator+(const T &a) const {
    DVectorBase<T,true> ret;
    for (unsigned int i=0; i<size; i++)  ret.v[i]=v[i]+a;
    return ret;
  }
  template<bool OWN1>
  inline void operator+=(const DVectorBase<T,OWN1> &a) {
    for (unsigned int i=0; i<size; i++)  v[i]+=a.v[i];
  }
  inline void operator+=(const T &a) {
    for (unsigned int i=0; i<size; i++)  v[i]+=a;
  }

  //subtraction
  template<bool OWN1>
  inline const DVectorBase<T,true> operator-(const DVectorBase<T,OWN1> &a) const {
    DVectorBase<T,true> ret;
    for (unsigned int i=0; i<size; i++)  ret.v[i]=v[i]-a.v[i];
    return ret;
  }
  inline const DVectorBase<T,true> operator-(const T &a) const {
    DVectorBase<T,true> ret;
    for (unsigned int i=0; i<size; i++)  ret.v[i]=v[i]-a;
    return ret;
  }
  template<bool OWN1>
  inline void operator-=(const DVectorBase<T,OWN1> &a) {
    for (unsigned int i=0; i<size; i++)  v[i]-=a.v[i];
  }
  inline void operator-=(const T &a) {
    for (unsigned int i=0; i<size; i++)  v[i]-=a;
  }

  //multiplication
  template<bool OWN1>
  inline const DVectorBase<T,true> operator*(const DVectorBase<T,OWN1> &a) const {
    DVectorBase<T,true> ret;
    for (unsigned int i=0; i<size; i++)  ret.v[i]=v[i]*a.v[i];
    return ret;
  }
  inline const DVectorBase<T,true> operator*(const T &a) const {
    DVectorBase<T,true> ret;
    for (unsigned int i=0; i<size; i++)  ret.v[i]=v[i]*a;
    return ret;
  }
  template<bool OWN1>
  inline void operator*=(const DVectorBase<T,OWN1> &a) {
    for (unsigned int i=0; i<size; i++)  v[i]*=a.v[i];
  }
  inline void operator*=(const T &a) {
    for (unsigned int i=0; i<size; i++)  v[i]*=a;
  }

  //division
  template<bool OWN1>
  inline const DVectorBase<T,true> operator/(const DVectorBase<T,OWN1> &a) const {
    DVectorBase<T,true> ret;
    for (unsigned int i=0; i<size; i++)  ret.v[i]=v[i]/a.v[i];
    return ret;
  }
  inline const DVectorBase<T,true> operator/(const T &a) const {
    DVectorBase<T,true> ret;
    for (unsigned int i=0; i<size; i++)  ret.v[i]=v[i]/a;
    return ret;
  }
  template<bool OWN1>
  inline void operator/=(const DVectorBase<T,OWN1> &a) {
    for (unsigned int i=0; i<size; i++)  v[i]/=a.v[i];
  }
  inline void operator/=(const T &a) {
    for (unsigned int i=0; i<size; i++)  v[i]/=a;
  }

  //conversion
  inline T* Data() {return v;}
  inline const T* Data() const {return v;}
  inline void Zero() {memset(v, 0,sizeof(T)*size);}
  inline void Fill(const T &a){for (size_type i=0; i<size; i++) v[i]=a;}
  DVectorBase<T,false> SubVec(size_type start,size_type end){return DVectorBase<T,false>(v+start,end-start+1);}

  //math
  inline void Negative(){for (int i=0; i<size; i++)  v[i]=-v[i];}
  inline T Len() const {return (T)sqrt((double)LenSqr());}
  inline T LenSqr() const {
    T ret=0;
    for (unsigned int i=0; i<size; i++)  ret+=v[i]*v[i];
    return (ret);
  }
  template<bool OWN1>
  inline T Dot(const DVectorBase<T,OWN1> &a) const {
    ZCHECK_EQ(size, a.size);
    T ret=0;
    for (unsigned int i=0; i<size; i++)  ret+=v[i]*a.v[i];
    return ret;
  }
  inline T Sum() const {
    T ret=0;
    for (size_type i=0; i<size; i++) ret+=v[i];
    return ret;
  }

  inline T Normalize() {T norm=Len(); *this/=norm; return norm;}
  inline DVectorBase<T,true> Normalized() const {return *this/Len();}

  template<bool OWN1>
  inline T DistTo(const DVectorBase<T,OWN1> &a) const {return (T)sqrt((double)DistToSqr(a));}
  template<bool OWN1>
  inline T DistToSqr(const DVectorBase<T,OWN1> &a) const 
  {
    T ret=0;
    for (unsigned int i=0; i<size; i++)  ret+=(v[i]-a.v[i])*(v[i]-a.v[i]);
    return (ret);
  }
  DVectorBase<T,true> RandomPerpendicularUnitVec() const 
  {
    DVectorBase<T,true> ret((T)0);
    ret[v[0]>(T)(1-EPS)?1:0]=(T)1;
    ret-=*this*ret.Dot(*this)/LenSqr();
    ret.Normalize();
    return ret;
  }

  //Min and Max
  inline T Max()
  {
    T maxv=v[0];
    for (unsigned int i=1; i<size; i++)  if (maxv<v[i]) maxv=v[i];
    return maxv;
  }
  inline int MaxPos()
  {
    T maxv=v[0];
    int pos=0;
    for (unsigned int i=1; i<size; i++) if (maxv<v[i]) {maxv=v[i];pos=i;}
    return pos;
  }
  inline T Min()
  {
    T minv=v[0];
    for (unsigned int i=1; i<size; i++) if (minv>v[i]) minv=v[i];
    return minv;
  }
  inline int MinPos()
  {
    T minv=v[0];
    int pos=0;
    for (unsigned int i=1; i<size; i++) if (minv>v[i]) {minv=v[i];pos=i;}
    return pos;
  }
  inline T AbsMax()
  {
    T maxv=v[0];
    for (unsigned int i=1; i<size; i++)  if (maxv<abs(v[i])) maxv=v[i];
    return maxv;
  }
  inline int AbsMaxPos()
  {
    T maxv=v[0];
    int pos=0;
    for (unsigned int i=1; i<size; i++) if (maxv<abs(v[i])) {maxv=v[i];pos=i;}
    return pos;
  }
  inline T AbsMin()
  {
    T minv=v[0];
    for (unsigned int i=1; i<size; i++) if (minv>abs(v[i])) minv=v[i];
    return minv;
  }
  inline int AbsMinPos()
  {
    T minv=v[0];
    int pos=0;
    for (unsigned int i=1; i<size; i++) if (minv>abs(v[i])) {minv=v[i];pos=i;}
    return pos;
  }

  // comparisons
  template<bool OWN1>
  bool operator== (const DVectorBase<T,OWN1>& y) const {return std::equal(begin(), end(), y.begin());}
  template<bool OWN1>
  bool operator< (const DVectorBase<T,OWN1>& y) const {return std::lexicographical_compare(begin(),end(), y.begin(), y.end());}
  template<bool OWN1>
  bool operator!= (const DVectorBase<T,OWN1>& y) const {return !(*this==y);}
  template<bool OWN1>
  bool operator> (const DVectorBase<T,OWN1>& y) const {return y<*this;}
  template<bool OWN1>
  bool operator<= (const DVectorBase<T,OWN1>& y) const {return !(y<*this);}
  template<bool OWN1>
  bool operator>= (const DVectorBase<T,OWN1>& y) const {return !(*this<y);}  

  inline bool operator==(const T &c) const
  {
    for (int i=0; i<size; i++)
      if (v[i]!=c) return false;
    return true;
  }
  inline bool operator!=(const T &c) const {return !(*this==c);}

  //IO
  friend inline ostream& operator<<(ostream& os,const DVectorBase<T,OWN> &me)
  {
    for (int i=0; i<me.size; i++)
      os<<me.v[i]<<' ';
    return os;
  }
  friend inline istream& operator>>(istream& is,DVectorBase<T,OWN> &me)
  {
    for (int i=0; i<me.size; i++)
      is>>me.v[i];
    return is;
  }
  void SaveToFileA(ostream &fo)
  {
    fo<<*this;
  }
  void LoadFromFileA(istream &fi)
  {
    fi>>*this;
  }
  void SaveToFileB(FILE *fp)
  {
    fwrite(v,sizeof(T),size,fp);
  }
  void LoadFromFileB(FILE *fp)
  {
    fread(v,sizeof(T),size,fp);
  }
  //dump
  inline void Print(ostream &os=zout) const
  {
    os<<"[ ";
    os<<*this;
    os<<"]\n";
  }

  //constructor
  DVectorBase() {v=NULL;size=0;}
  ~DVectorBase(){}
};
//////////////////////////////////////////////////////////////////////////
//define base
template<typename T, bool OWN=true>
struct DVector : public DVectorBase<T,OWN>
{
// Need partial specified.
};

//specify whole class for own
template<typename T>
struct DVector<T,true> : public DVectorBase<T,true>
{
  using DVectorBase<T,true>::v;
  using DVectorBase<T,true>::size;
  DVector(){}
  DVector(size_type n){v=new T[n]; size=n;}
  DVector(size_type n,const T& v);
  DVector(T *a, size_type n){v=new T[n]; size=n; for (size_type i=0; i<n; i++) v[i]=a[i];}
  DVector(const DVector<T,true>& a){*this=a;}

  template<bool OWN1>
  DVector(const DVectorBase<T,OWN1>& vec){v=new T[vec.size]; size=vec.size; for (zuint i=0; i<size; i++) v[i]=vec.v[i];}
  ~DVector(){if (v) delete[] v;}
  //copy
  const DVector<T,true> &operator=(const DVector<T,true>& a){SetSize(a.size); for (unsigned int i=0; i<size; i++) v[i]=(T)a[i]; return *this;}
  template <typename T1, bool OWN1>
  const DVector<T,true> &operator=(const DVectorBase<T1,OWN1>& a){SetSize(a.size); for (unsigned int i=0; i<size; i++) v[i]=(T)a[i]; return *this;}

  void SetSize(size_type n){if (n==size) return; if (v) delete v; v=new T[n]; size=n;}
};

//specify whole class for not own
template<typename T>
struct DVector<T,false> : public DVectorBase<T,false>
{
  using DVectorBase<T,false>::v;
  using DVectorBase<T,false>::size;
  DVector(size_type n,const T& v){v=new T[n]; size=n; for (size_type i=0; i<n; i++)v[i]=v;}
  DVector(T *a, size_type n){v=a; size=n;}
  DVector(const DVector<T,false>& a){v=a.v;size=a.size;}
  template<bool OWN1>
  DVector(const DVectorBase<T,OWN1>& vec){v=vec.v; size=vec.size;}
  ~DVector(){}

  //copy
  template <bool OWN1>
  inline const DVector<T,false> &operator=(const DVector<T,OWN1>& a){v=a.v; return *this;}
  template <bool OWN1>
  void SetHolder(const DVector<T,OWN1>& a){v=a.v; size=a.size; return *this;}
  void SetHolder(const T* a, const int n){v=a.v; size=n; return *this;}
};

typedef DVector<zint8> DVectori8;
typedef DVector<zuint8> DVectorui8;
typedef DVector<zint16> DVectori16;
typedef DVector<zuint8> DVectorui16;
typedef DVector<zint32> DVectori32;
typedef DVector<zuint32> DVectorui32;
typedef DVector<zint64> DVectori64;
typedef DVector<zuint64> DVectorui64;
typedef DVector<zfloat32> DVectorf32;
typedef DVector<zfloat64> DVectorf64;


typedef DVector<float,true> DVectorf;
typedef DVector<double,true> DVectord;
typedef DVector<int,true> DVectori;
typedef DVector<zuint,true> DVectorui;
}
